package mr.ali.webvideo.utils;

import lombok.extern.slf4j.Slf4j;
import org.springframework.util.StringUtils;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import java.io.StringReader;
import java.security.MessageDigest;
import java.util.*;

/**
 * 微信支付工具类
 */
@Slf4j
public class WxPayUtil {

    /**
     * 生成随机字符串
     *
     * @return 随机字符串
     */
    public static String generateNonceStr() {
        return UUID.randomUUID().toString().replaceAll("-", "");
    }

    /**
     * 生成时间戳
     *
     * @return 时间戳
     */
    public static String generateTimestamp() {
        return String.valueOf(System.currentTimeMillis() / 1000);
    }

    /**
     * 生成签名
     *
     * @param params 参数
     * @param key    API密钥
     * @return 签名
     */
    public static String generateSignature(Map<String, String> params, String key) {
        // 按照参数名ASCII码从小到大排序
        Map<String, String> sortedParams = new TreeMap<>(params);

        // 拼接参数
        StringBuilder sb = new StringBuilder();
        for (Map.Entry<String, String> entry : sortedParams.entrySet()) {
            String k = entry.getKey();
            String v = entry.getValue();
            if (StringUtils.hasText(v) && !"sign".equals(k) && !"key".equals(k)) {
                sb.append(k).append("=").append(v).append("&");
            }
        }
        sb.append("key=").append(key);

        // MD5加密
        String sign = md5(sb.toString()).toUpperCase();
        log.debug("生成签名: {}", sign);
        return sign;
    }

    /**
     * MD5加密
     *
     * @param data 数据
     * @return 加密结果
     */
    public static String md5(String data) {
        try {
            MessageDigest md = MessageDigest.getInstance("MD5");
            byte[] array = md.digest(data.getBytes("UTF-8"));
            StringBuilder sb = new StringBuilder();
            for (byte item : array) {
                sb.append(Integer.toHexString((item & 0xFF) | 0x100).substring(1, 3));
            }
            return sb.toString();
        } catch (Exception e) {
            log.error("MD5加密失败", e);
            return null;
        }
    }

    /**
     * 将Map转换为XML
     *
     * @param params 参数
     * @return XML字符串
     */
    public static String mapToXml(Map<String, String> params) {
        StringBuilder sb = new StringBuilder();
        sb.append("<xml>");
        for (Map.Entry<String, String> entry : params.entrySet()) {
            String k = entry.getKey();
            String v = entry.getValue();
            if ("sign".equals(k)) {
                sb.append("<").append(k).append(">").append(v).append("</").append(k).append(">");
            } else {
                sb.append("<").append(k).append("><![CDATA[").append(v).append("]]></").append(k).append(">");
            }
        }
        sb.append("</xml>");
        return sb.toString();
    }

    /**
     * 将XML转换为Map
     *
     * @param xml XML字符串
     * @return 参数Map
     */
    public static Map<String, String> xmlToMap(String xml) {
        Map<String, String> map = new HashMap<>();
        try {
            DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
            DocumentBuilder builder = factory.newDocumentBuilder();
            Document document = builder.parse(new InputSource(new StringReader(xml)));
            Element root = document.getDocumentElement();
            NodeList nodeList = root.getChildNodes();
            for (int i = 0; i < nodeList.getLength(); i++) {
                Node node = nodeList.item(i);
                if (node.getNodeType() == Node.ELEMENT_NODE) {
                    map.put(node.getNodeName(), node.getTextContent());
                }
            }
        } catch (Exception e) {
            log.error("XML解析失败", e);
        }
        return map;
    }

    /**
     * 检查签名是否正确
     *
     * @param params 参数
     * @param key    API密钥
     * @return 是否正确
     */
    public static boolean checkSignature(Map<String, String> params, String key) {
        String sign = params.get("sign");
        if (sign == null) {
            return false;
        }
        String calculatedSign = generateSignature(params, key);
        return sign.equals(calculatedSign);
    }

    /**
     * 生成订单号
     *
     * @return 订单号
     */
    public static String generateOrderNo() {
        // 生成格式：年月日时分秒+6位随机数
        String date = new java.text.SimpleDateFormat("yyyyMMddHHmmss").format(new Date());
        String random = String.valueOf((int) ((Math.random() * 9 + 1) * 100000));
        return date + random;
    }
}
